---
title: SecureStore
description: A library that provides a way to encrypt and securely store key-value pairs locally on the device.
sourceCodeUrl: 'https://github.com/expo/expo/tree/sdk-52/packages/expo-secure-store'
packageName: 'expo-secure-store'
iconUrl: '/static/images/packages/expo-secure-store.png'
platforms: ['android', 'ios', 'tvos']
---

import APISection from '~/components/plugins/APISection';
import { APIInstallSection } from '~/components/plugins/InstallSection';
import {
  ConfigPluginExample,
  ConfigReactNative,
  ConfigPluginProperties,
} from '~/ui/components/ConfigSection';
import { SnackInline } from '~/ui/components/Snippet';

`expo-secure-store` provides a way to encrypt and securely store key-value pairs locally on the device. Each Expo project has a separate storage system and has no access to the storage of other Expo projects.

**Size limit for a value is 2048 bytes. An attempt to store larger values may fail. Currently, we print a warning when the limit is reached, however, in a future SDK version an error might be thrown.**

**The `requireAuthentication` option is not supported in Expo Go when biometric authentication is available due to a missing `NSFaceIDUsageDescription` key.**

> This API is not compatible with devices running Android 5 or lower.

## Installation

<APIInstallSection />

## Configuration in app config

You can configure `expo-secure-store` using its built-in [config plugin](/config-plugins/introduction/) if you use config plugins in your project ([Continuous Native Generation (CNG)](/workflow/continuous-native-generation/)). The plugin allows you to configure various properties that cannot be set at runtime and require building a new app binary to take effect. If your app does **not** use CNG, then you'll need to manually configure the library.

<ConfigPluginExample>

```json app.json
{
  "expo": {
    "plugins": [
      [
        "expo-secure-store",
        {
          "configureAndroidBackup": true,
          "faceIDPermission": "Allow $(PRODUCT_NAME) to access your Face ID biometric data."
        }
      ]
    ]
  }
}
```

</ConfigPluginExample>

<ConfigPluginProperties
  properties={[
    {
      name: 'configureAndroidBackup',
      platform: 'android',
      description:
        'A boolean indicating whether to configure automatic Android backup to work correctly with `expo-secure-store`. [Learn more](#android-auto-backup).',
      default: 'true',
    },
    {
      name: 'faceIDPermission',
      platform: 'ios',
      description: 'A string to set the [`NSFaceIDUsageDescription`](#ios) permission message.',
      default: '"Allow $(PRODUCT_NAME) to access your Face ID biometric data."',
    },
  ]}
/>

<ConfigReactNative>

Add `NSFaceIDUsageDescription` key to **Info.plist**:

```xml Info.plist
<key>NSFaceIDUsageDescription</key>
<string>Allow $(PRODUCT_NAME) to access your Face ID biometric data.</string>
```

</ConfigReactNative>

## Platform value storage

### Android

On Android, values are stored in [`SharedPreferences`](https://developer.android.com/training/data-storage/shared-preferences), encrypted with [Android's Keystore system](https://developer.android.com/training/articles/keystore.html).

### iOS

> For iOS standalone apps, data stored with `expo-secure-store` can persist across app installs.

On iOS, values are stored using the [keychain services](https://developer.apple.com/documentation/security/keychain_services) as `kSecClassGenericPassword`. iOS has the additional option of being able to set the value's `kSecAttrAccessible` attribute, which controls when the value is available to be fetched.

## Data persistence

`expo-secure-store` is designed to provide a persistent data storage solution across app restarts and updates. However, it is important not to rely on it as a single source of truth for irreplaceable, critical data. Data saved using `expo-secure-store` will not be preserved upon app uninstallation.
Additionally, any data protected with the `requireAuthentication` option set to `true` will become inaccessible if there are changes to the user's biometric settings, such as adding a new fingerprint.

#### Exempting encryption prompt

Apple App Store Connect prompts you to select the type of encryption algorithm your app implements. This is known as **Export Compliance Information**. It is asked when publishing the app or submitting for TestFlight.

When using `expo-secure-store`, you can set the [`ios.config.usesNonExemptEncryption`](../config/app/#usesnonexemptencryption) property to `false` in the app config:

{/* prettier-ignore */}
```json app.json
{
  "expo": {
    "ios": {
      "config": {
        "usesNonExemptEncryption": false
      }
      /* @hide ... */ /* @end */
    }
  }
}
```

Setting this property automatically handles the compliance information prompt.

## Android Auto Backup

[Android Auto Backup for Apps](https://developer.android.com/identity/data/autobackup) automatically backs up a user's data from apps that target and run on Android 6.0 (API level 23) or higher.

The Auto Backup system has to be configured to exclude `expo-secure-store` shared preferences entries, as it's impossible to decrypt them after restoring the backup &mdash; app's entries are deleted from the Android Key Store when the app is uninstalled.

If your app doesn't have any custom backup configuration, `expo-secure-store` will automatically configure the Auto Backup system to ignore the `expo-secure-store` data.

If you are using your own Auto Backup configuration, you should exclude the `SecureStore` under the `sharedpref` domain and set the `configureAndroidBackup` to `false` in the [config plugin configuration](#example-appjson-with-config-plugin).

```xml
<!--  Auto Backup configuration for Android 12 and higher -->
<data-extraction-rules>
  <cloud-backup>
    <include domain="sharedpref" path="."/>
    <exclude domain="sharedpref" path="SecureStore"/>
  </cloud-backup>
  <device-transfer>
    <include domain="sharedpref" path="."/>
    <exclude domain="sharedpref" path="SecureStore"/>
  </device-transfer>
</data-extraction-rules>
```

```xml
<!--  Auto Backup configuration for Android 11 and lower -->
<full-backup-content>
  <include domain="sharedpref" path="."/>
  <exclude domain="sharedpref" path="SecureStore"/>
</full-backup-content>
```

## Usage

<SnackInline label='SecureStore' dependencies={['expo-secure-store']} platforms={['ios', 'android']}>

```jsx
import { useState } from 'react';
import { Text, View, StyleSheet, TextInput, Button } from 'react-native';
import * as SecureStore from 'expo-secure-store';

async function save(key, value) {
  await SecureStore.setItemAsync(key, value);
}

async function getValueFor(key) {
  let result = await SecureStore.getItemAsync(key);
  if (result) {
    alert("🔐 Here's your value 🔐 \n" + result);
  } else {
    alert('No values stored under that key.');
  }
}

export default function App() {
  const [key, onChangeKey] = useState('Your key here');
  const [value, onChangeValue] = useState('Your value here');

  return (
    <View style={styles.container}>
      <Text style={styles.paragraph}>Save an item, and grab it later!</Text>
      {/* @hide Add some TextInput components... */}

      <TextInput
        style={styles.textInput}
        clearTextOnFocus
        onChangeText={text => onChangeKey(text)}
        value={key}
      />
      <TextInput
        style={styles.textInput}
        clearTextOnFocus
        onChangeText={text => onChangeValue(text)}
        value={value}
      />
      {/* @end */}
      <Button
        title="Save this key/value pair"
        onPress={() => {
          save(key, value);
          onChangeKey('Your key here');
          onChangeValue('Your value here');
        }}
      />
      <Text style={styles.paragraph}>🔐 Enter your key 🔐</Text>
      <TextInput
        style={styles.textInput}
        onSubmitEditing={event => {
          getValueFor(event.nativeEvent.text);
        }}
        placeholder="Enter the key for the value you want to get"
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    paddingTop: 10,
    backgroundColor: '#ecf0f1',
    padding: 8,
  },
  paragraph: {
    marginTop: 34,
    margin: 24,
    fontSize: 18,
    fontWeight: 'bold',
    textAlign: 'center',
  },
  textInput: {
    height: 35,
    borderColor: 'gray',
    borderWidth: 0.5,
    padding: 4,
  },
});
```

</SnackInline>

## API

```js
import * as SecureStore from 'expo-secure-store';
```

<APISection packageName="expo-secure-store" apiName="SecureStore" />
